#include <stdarg.h>
#include <string.h>
#include <stdbool.h>
#include "screen_io.h"
#include "ili9320.h"


#define screen_font_from_c
#include "screen_font.h"


uint16_t
fontColor = White,                     //默认字体颜色
fontBkColor = Black,                   //默认字体背景颜色
fix_fontColor = White,                 //标准字体颜色
fix_fontBkColor = Black;               //标准字体背景颜色
int8_t
cur_col = 0,                           //当前列位置
cur_row = 0,                           //当前行位置
cur_width = LCD_WIDTH / FONT_STEP_X,
cur_height = LCD_HEIGHT / FONT_STEP_Y;
bool flagScroll = true;                //输出字符串自动换行标识
uint16_t
cur_x_ofs = 0,                         //字符输出窗体x偏移
cur_y_ofs = 0;                         //字符输出窗体y偏移

void scr_setfullTextWindow(void)
{
    cur_x_ofs = 0;
    cur_y_ofs = 0;
    cur_width = LCD_WIDTH / FONT_STEP_X;
    cur_height = LCD_HEIGHT / FONT_STEP_Y;
}

void scr_setTextWindow(uint16_t x, uint16_t y, uint8_t maxCol, uint8_t maxRow)
{
    cur_x_ofs = x;
    cur_y_ofs = y;
    cur_width = ((maxCol * FONT_STEP_X + x) >= LCD_WIDTH) ? (LCD_WIDTH - x) / FONT_STEP_X : maxCol;
    cur_height = ((maxRow * FONT_STEP_Y + y) >= LCD_HEIGHT) ? (LCD_HEIGHT - y) / FONT_STEP_Y : maxRow;
}
/****************************************************************************
*LCD设置显示字符串时是否自动换行
****************************************************************************/
void scr_setScroll(uint8_t flag)
{
    flagScroll = flag;
}
/****************************************************************************
*LCD设置当前行和列位置
****************************************************************************/
void scr_gotoxy(int8_t col, int8_t row)
{
    cur_col = col;
    cur_row = row;
}
/****************************************************************************
*LCD获取当前行号
****************************************************************************/
int8_t scr_getCurRow(void)
{
    return cur_row;
}
/****************************************************************************
*LCD设置字体颜色
****************************************************************************/
void scr_fontColor(unsigned short fontC, unsigned short fontBkC)
{
    fontBkColor = fix_fontBkColor = fontBkC;
    fontColor = fix_fontColor = fontC;
}
/****************************************************************************
*LCD反转字体颜色
****************************************************************************/
void scr_fontColorInvers(void)
{
    fontBkColor = fix_fontColor;
    fontColor = fix_fontBkColor;
}
/****************************************************************************
*LCD设置为正常字体颜色
****************************************************************************/
void scr_fontColorNormal(void)
{
    fontColor = fix_fontColor;
    fontBkColor = fix_fontBkColor;
}



/****************************************************************************
 *LCD画线函数
 ****************************************************************************/
void scr_Line(uint16_t x0, uint16_t y0, uint16_t x1, uint16_t y1, uint16_t color)
{
    uint16_t x, y;
    uint16_t dx;
    uint16_t dy;

    if (y0 == y1)
    {
        if (x0 <= x1)
        {
            x = x0;
        }
        else
        {
            x = x1;
            x1 = x0;
        }
        while (x <= x1)
            LCD_SetPoint(x++, y0, color);
        return;
    }
    else if (y0 > y1)
        dy = y0 - y1;
    else
        dy = y1 - y0;

    if (x0 == x1)
    {
        if (y0 <= y1)
        {
            y = y0;
        }
        else
        {
            y = y1;
            y1 = y0;
        }
        while (y <= y1)
            LCD_SetPoint(x0, y++, color);
        return;
    }
    else if (x0 > x1)
    {
        dx = x0 - x1;
        x = x1;
        x1 = x0;
        y = y1;
        y1 = y0;
    }
    else
    {
        dx = x1 - x0;
        x = x0;
        y = y0;
    }

    if (dx == dy)
    {
        while (x <= x1)
        {
            if (y > y1)	y--;
            else		y++;
            LCD_SetPoint(x++, y, color);
        }
    }
    else
    {
        LCD_SetPoint(x, y, color);
        if (y < y1)
        {
            if (dx > dy)
            {
                s16 p = dy * 2 - dx;
                s16 twoDy = 2 * dy;
                s16 twoDyMinusDx = 2 * (dy - dx);
                while (x < x1)
                {
                    if (p < 0)
                        p += twoDy;
                    else
                    {
                        y++;
                        p += twoDyMinusDx;
                    }
                    LCD_SetPoint(x++, y, color);
                }
            }
            else
            {
                s16 p = dx * 2 - dy;
                s16 twoDx = 2 * dx;
                s16 twoDxMinusDy = 2 * (dx - dy);
                while (y < y1)
                {
                    if (p < 0)
                        p += twoDx;
                    else
                    {
                        x++;
                        p += twoDxMinusDy;
                    }
                    LCD_SetPoint(x, y++, color);
                }
            }
        }
        else
        {
            if (dx > dy)
            {
                s16 p = dy * 2 - dx;
                s16 twoDy = 2 * dy;
                s16 twoDyMinusDx = 2 * (dy - dx);
                while (x < x1)
                {
                    if (p < 0)
                    {
                        p += twoDy;
                    }
                    else
                    {
                        y--;
                        p += twoDyMinusDx;
                    }
                    LCD_SetPoint(++x, y, color);
                }
            }
            else
            {
                s16 p = dx * 2 - dy;
                s16 twoDx = 2 * dx;
                s16 twoDxMinusDy = 2 * (dx - dy);
                while (y1 < y)
                {
                    if (p < 0)
                    {
                        p += twoDx;
                    }
                    else
                    {
                        x++;
                        p += twoDxMinusDy;
                    }
                    LCD_SetPoint(x, --y, color);
                }
            }
        }
    }
}

/****************************************************************************
 *LCD画矩形函数
 ****************************************************************************/
void scr_Rectangle(uint16_t x0, uint16_t y0, uint16_t x1, uint16_t y1, uint16_t color, uint8_t fill)
{
    uint16_t h = y1 - y0;
    if (fill)
    {
        for (h++; x0 <= x1; x0++)
            LCD_VLine(x0, y0, h, color);
        return;
    }
    LCD_VLine(x0, y0, h, color);
    scr_Line(x0, y0, x1, y0, color);
    scr_Line(x0, y1, x1, y1, color);
    LCD_VLine(x1, y0, h, color);
}

/****************************************************************************
 *LCD画正方形函数
 ****************************************************************************/
void  scr_Square(uint16_t x0, uint16_t y0, uint16_t with, uint16_t color, uint8_t fill)
{
    scr_Rectangle(x0, y0, x0 + with, y0 + with, color, fill);
}

/**
* @brief  Draws a circle.
* @param  Xpos: X position
* @param  Ypos: Y position
* @param  Radius: Circle radius
* @retval None
*/
void src_Circle(uint16_t Xpos, uint16_t Ypos, uint16_t Radius, uint16_t color)
{
    int32_t  D;       /* Decision Variable */
    uint32_t  CurX;   /* Current X Value */
    uint32_t  CurY;   /* Current Y Value */

    D = 3 - (Radius << 1);
    CurX = 0;
    CurY = Radius;

    while (CurX <= CurY)
    {
        LCD_SetPoint((Xpos + CurX), (Ypos - CurY), color);

        LCD_SetPoint((Xpos - CurX), (Ypos - CurY), color);

        LCD_SetPoint((Xpos + CurY), (Ypos - CurX), color);

        LCD_SetPoint((Xpos - CurY), (Ypos - CurX), color);

        LCD_SetPoint((Xpos + CurX), (Ypos + CurY), color);

        LCD_SetPoint((Xpos - CurX), (Ypos + CurY), color);

        LCD_SetPoint((Xpos + CurY), (Ypos + CurX), color);

        LCD_SetPoint((Xpos - CurY), (Ypos + CurX), color);

        if (D < 0)
        {
            D += (CurX << 2) + 6;
        }
        else
        {
            D += ((CurX - CurY) << 2) + 10;
            CurY--;
        }
        CurX++;
    }
}

/**
* @brief  Draws an ellipse on LCD.
* @param  Xpos: X position
* @param  Ypos: Y position
* @param  XRadius: Ellipse X radius
* @param  YRadius: Ellipse Y radius
* @retval None
*/
void src_Ellipse(int Xpos, int Ypos, int XRadius, int YRadius, uint16_t color)
{
    int x = 0, y = -YRadius, err = 2 - 2 * XRadius, e2;
    float K = 0, rad1 = 0, rad2 = 0;

    rad1 = XRadius;
    rad2 = YRadius;

    K = (float)(rad2 / rad1);

    do
    {
        LCD_SetPoint((Xpos - (uint16_t)(x / K)), (Ypos + y), color);
        LCD_SetPoint((Xpos + (uint16_t)(x / K)), (Ypos + y), color);
        LCD_SetPoint((Xpos + (uint16_t)(x / K)), (Ypos - y), color);
        LCD_SetPoint((Xpos - (uint16_t)(x / K)), (Ypos - y), color);

        e2 = err;
        if (e2 <= x)
        {
            err += ++x * 2 + 1;
            if (-y == x && e2 <= y) e2 = 0;
        }
        if (e2 > y) err += ++y * 2 + 1;
    } while (y <= 0);
}

/****************************************************************************
 *LCD显示字符函数
 ****************************************************************************/
void scr_putc(char c , int8_t *col, int8_t *row)
{
    if (*col >= cur_width && flagScroll)
    {
        *col = 0;
        (*row)++;
    }

    if (*row >= cur_height && flagScroll)
        *row = 0;

    switch (c)
    {
    case '\t':
        *col = ((*col + 8) >> 3) << 3;
        break;
    case '\n':
        (*row)++;
        *col = 0;
        break;
    case '\r':
        break;
    default:
        if (*col >= 0 && *col < cur_width && *row >= 0 && *row < cur_height)
            LCD_PutChar(
                (uint16_t)*col * FONT_STEP_X + cur_x_ofs,
                (uint16_t)*row * FONT_STEP_Y + cur_y_ofs,
                c,
                fontColor,
                fontBkColor
            );
        (*col)++;
    }
}

/****************************************************************************
 *LCD显示字符串函数
 ****************************************************************************/
void scr_puts(const char *str)
{
    while (*str)
	{
        scr_putc(*str++, &cur_col, &cur_row);
	}
}
/****************************************************************************
*LCD设置显示字符串位置函数
****************************************************************************/
void scr_putsat(const char *str, int8_t col, int8_t row)
{
    while (*str)
	{
        scr_putc(*str++, &col, &row);
	}
}

/****************************************************************************
 *LCD将该行后面以空格填充
 ****************************************************************************/
void scr_clrEndl(void)
{
    while (cur_col < cur_width)
	{
        scr_putc(' ', &cur_col, &cur_row);
	}
}

/****************************************************************************
 *将数字转换为字符串
 ****************************************************************************/
void scr_itoa(long val, int radix, int len)
{
    uint8_t c, r, sgn = 0, pad = ' ';
    uint8_t s[20], i = 0;
    unsigned long v;

    if (radix < 0)
    {
        radix = -radix;
        if (val < 0)
        {
            val = -val;
            sgn = '-';
        }
    }
    v = val;
    r = radix;
    if (len < 0)
    {
        len = -len;
        pad = '0';
    }
    if (len > 20)
        return;
    do
    {
        c = (uint8_t)(v % r);
        if (c >= 10) c += 7;
        c += '0';
        s[i++] = c;
        v /= r;
    }
    while (v);

    if (sgn) s[i++] = sgn;
    while (i < len)	s[i++] = pad;
    do
        scr_putc(s[--i], &cur_col, &cur_row);
    while (i);
}

/****************************************************************************
 *将浮点数转换为字符串
 ****************************************************************************/
void scr_ftoa(double val, int len)
{
    if (val < 0)
    {
        scr_putc('-', &cur_col, &cur_row);
        val = -val;
    }
    long n = (long)val;
    scr_itoa(n, 10, len);
    scr_putc('.', &cur_col, &cur_row);
    n = (int)(val * 100.0) % 100;
    scr_itoa(n, 10, -2);
}

/****************************************************************************
 *LCD使用printf格式输出字符串
 ****************************************************************************/
void scr_printf(const char *str, ...)
{
    va_list arp;
    int d, r, w, s, l;
    va_start(arp, str);

    while ((d = *str++) != 0)
    {
        if (d != '%')
        {
            scr_putc(d, &cur_col, &cur_row);
            continue;
        }
        d = *str++;
        w = r = s = l = 0;
        if (d == '0')
        {
            d = *str++;
            s = 1;
        }
        while ((d >= '0') && (d <= '9'))
        {
            w += w * 10 + (d - '0');
            d = *str++;
        }
        if (s) w = -w;
        if (d == 'l')
        {
            l = 1;
            d = *str++;
        }
        if (!d) break;
        if (d == 's')
        {
            scr_puts(va_arg(arp, char *));
            continue;
        }
        if (d == 'c')
        {
            scr_putc((char)va_arg(arp, int), &cur_col, &cur_row);
            continue;
        }
        if (d == 'f')
        {
            scr_ftoa((double)va_arg(arp, double), w);
            continue;
        }
        if (d == 'u') r = 10;
        if (d == 'd') r = -10;
        if (d == 'X' || d == 'x') r = 16; // 'x' added by mthomas in increase compatibility
        if (d == 'b') r = 2;
        if (d == '%')
        {
            scr_putc(d, &cur_col, &cur_row);
            continue;
        }

        if (!r) break;
        if (l)
        {
            scr_itoa((long)va_arg(arp, long), r, w);
        }
        else
        {
            if (r > 0)
                scr_itoa((unsigned long)va_arg(arp, int), r, w);
            else
                scr_itoa((long)va_arg(arp, int), r, w);
        }
    }
    va_end(arp);
}

/****************************************************************************
 *
 ****************************************************************************/
const char hexAlpha[] = "0123456789ABCDEF";
void scr_dump(const uint8_t *buff, int sz)
{
    int i;
    for (i = 0; i < sz; i++)
    {
        scr_putc(hexAlpha[(buff[i] >> 4) & 0x0F], &cur_col, &cur_row);
        scr_putc(hexAlpha[buff[i] & 0x0F], &cur_col, &cur_row);
    }
}

/****************************************************************************
 *显示窗体函数
 *x0,y0:起始位置
 *colSz,rowSz:列数，行数
 *cBorder:边界颜色
 *cFill:填充颜色
 *cText:字体颜色
 ****************************************************************************/
void win_showWindow(
    uint16_t x0, uint16_t y0,
    uint8_t colSz, uint8_t rowSz,
    uint16_t cBorder,
    uint16_t cFill,
    uint16_t cText
)
{
    uint16_t x1 = x0 + (uint16_t)colSz * FONT_STEP_X + BORDER_PADDING * 2;
    uint16_t y1 = y0 + (uint16_t)rowSz * FONT_STEP_Y + BORDER_PADDING * 2;
    if(x1 > LCD_WIDTH)
    {
        x1 = LCD_WIDTH;
    }
    if(y1 > LCD_HEIGHT)
    {
        y1 = LCD_HEIGHT;
    }
    scr_Rectangle(x0, y0, x1, y1, cBorder, false);
    scr_Rectangle(x0 + 1, y0 + 1, x1 - 1, y1 - 1, cBorder, false);
    scr_Rectangle(x0 + 2, y0 + 2, x1 - 2, y1 - 2, cBorder, false);
    scr_Rectangle(x0 + 3, y0 + 3, x1 - 3, y1 - 3, cFill, true);
    scr_setTextWindow(
        x0 + BORDER_PADDING,
        y0 + BORDER_PADDING,
        (x1 - x0 - BORDER_PADDING * 2) / FONT_STEP_X,
        (y1 - y0 - BORDER_PADDING * 2) / FONT_STEP_Y
    );
    scr_fontColor(cText, cFill);
}

#define WIN_WIDTH	32
#define WIN_HEIGHT	8
#define WIN_X_TOP	FONT_STEP_X * 4 - BORDER_PADDING
#define WIN_Y_LEFT	FONT_STEP_Y * 4 - BORDER_PADDING

//#if (USE_KEYBOARD == 2)
//const TPKey_t kbdWinC = TPKEY(
//                            WIN_X_TOP,
//                            WIN_Y_LEFT,
//                            WIN_WIDTH   *FONT_STEP_X,
//                            WIN_HEIGHT *FONT_STEP_Y,
//                            KEY_C, NULL);
//const TPKey_p kbdWin[] =
//{
//    &kbdWinC,
//    NULL
//};
//#endif

/****************************************************************************
*LCD显示窗体函数
****************************************************************************/
void win_showWin(uint16_t cBorder, uint16_t cFill, uint16_t cText)
{
    win_showWindow(
        WIN_X_TOP,
        WIN_Y_LEFT,
        WIN_WIDTH, WIN_HEIGHT,
        cBorder, cFill, cText
    );
    //    SetTouchKeys(kbdWin);
    scr_gotoxy(0, 0);
    scr_setScroll(true);
}

/****************************************************************************
 *LCD显示错误提示窗
 ****************************************************************************/
void win_showErrorWin(void)
{
    win_showWin(Yellow, Red, White);
}

/****************************************************************************
 *LCD显示消息输出窗
 ****************************************************************************/
void win_showMsgWin(void)
{
    win_showWin(Magenta, Blue2, Black);
}

/****************************************************************************
 *LCD显示进度条
 ****************************************************************************/
void win_showProgressBar(uint16_t x, uint16_t y, uint16_t dx, uint16_t dy, uint8_t p)
{
    uint16_t n = (dx) * p / 100;
    scr_Rectangle(x, y, x + dx, y + dy, Red, false);
    scr_Rectangle(x + 1, y + 1, x + dx - 1, y + dy - 1, Red, false);
    scr_Rectangle(x + 2 + n - 1, y + 2, x + dx - 2, y + dy - 2, Black, true);
    scr_Rectangle(x + 2, y + 2, x + n + 1, y + dy - 2, Yellow, true);
}

/****************************************************************************
 *LCD显示菜单条
 ****************************************************************************/
void win_showMenu(uint16_t x, uint16_t y, uint8_t col, uint8_t row, char *title)
{
    win_showWindow(0, 0, col, 1, Green, Magenta, Black);
    scr_gotoxy(0, 0);
    scr_printf(title);
    win_showWindow(0, 25, col, row, Green, Cyan, Blue);
    scr_gotoxy(0, 0);
    scr_setScroll(false);
}



/****************************************************************************
 *LCD显示带滚动条的窗体
 ***************************************************************************/
void win_showMenuScroll(
    uint16_t x, uint16_t y,
    uint8_t col, uint8_t row,
    uint8_t startPos, uint8_t selPos, uint8_t lines
)
{
    uint16_t x1 = x + (uint16_t)col * FONT_STEP_X + 10;
    uint16_t y1 = y + (uint16_t)row * FONT_STEP_Y + 10;
    uint16_t h = (y1 - y) - 4;
    uint16_t n = row > lines ? h : h * row / lines;
    uint16_t ofs = row > lines ? 0 : h * startPos / lines;
    win_showWindow(x, y, col, row, White, Blue, Yellow);
    scr_Rectangle(x1, y, x1 + 7, y1, White, true);
    scr_Rectangle(x1 - 1, y + ofs + 2, x1 + 4, y + ofs + n, Blue2, true);

    scr_setTextWindow(x + 5, y + 5, col, row);
    scr_gotoxy(0, -(int8_t)startPos);
    scr_setScroll(false);
}

